<?php

/**
 * This file is part of the Codizer package.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @copyright   Copyright (c) 2010 Advisa (http://www.advisa.fr)
 * @author      Codizer Core Team <team@codizer.org>
 * @package     Codizer
 */

class f_test_TestBuilder
{
	private $actionName;
	private $moduleName;
	
	/**
	 * @return f_test_Builder
	 */
	private function __construct()
	{
		return $this;
	}
	
	/**
	 * Get instance
	 *
	 * @return f_test_Builder
	 */
	public static function getInstance()
	{
		return new self();
	}

	/**
	 * Set the module name to generate the unit test
	 *
	 * @param string $value
	 * @return f_builder_TestBuilder
	 */
	public function setModuleName($value)
	{
		$this->moduleName = $value;
		return $this;
	}

	/**
	 * Set the name to generate the unit test
	 *
	 * @param string $value
	 * @return f_builder_TestBuilder
	 */
	public function setActionName($value)
	{
		$args = explode("_", $value);
		if(count($args) > 1)
		{
			$args[count($args)-1] = ucfirst($args[count($args)-1]);
			$this->actionName = implode("_", $args);
		}
		$this->actionName = $value;
		return $this;
	}

    /**
     * Generate the unit tests files.
     */
    public function build()
    {
        $sources = $this->getActionDirectory();
        //var_dump($sources);
        if(!empty($sources) && is_array($sources))
        {
            $i = 0;
            foreach($sources as $source)
            {
                if(!file_exists($source['destPath']))
                {
                    try
                    {
                        $args = Array($source['className'], $source['filePath'], $source['testClassName'], $source['destPath']);

                        $reflector = new ReflectionClass('PHPUnit_Util_Skeleton_Test');
                        $skeleton = $reflector->newInstanceArgs($args);
                        $skeleton->write();
                    }

                    catch (Exception $e)
                    {
                        print $e->getMessage() . "\n";
                        exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT);
                    }

                    echo COLOR_GREEN."Wrote skeleton".COLOR_NORMAL." -> ".$skeleton->getOutClassName() . " to " .$skeleton->getOutSourceFile()."\n";
                    $i++;
                }
            }

            echo $i . " skeleton writed.\n";
        }
        else
        {
            echo "There are any file in the folder\n";
        }
    }

	/**
	 * Get the module and action files
	 *
	 * @param string $basePath
	 * @return array
	 */
	private function getActionDirectory()
	{
        if(!empty($this->moduleName))
        {
            if(!empty($this->actionName))
            {
                $resolver = f_file_Resolver::getInstance();

                $mainDir = array("Action" => "actions", 
                                 "documents",
                                 "forms",
                                 "Service" => "services",
                                 "View" => "views");

                $args = explode("_", $this->actionName);
                $nb = count($args);
                if($nb > 1 && in_array($args[0], $mainDir))
                {
                    $classType = $args[0];
                    unset($args[0]);
                    $actionName = implode("_", $args);
                }
                else
                {
                    throw new Exception("Bad syntaxe");
                }

                $suffix = array_search($classType, $mainDir);
                $suffix = is_string($suffix) ? $suffix : "";
                
                $className = "w_".$this->moduleName."_".$classType."_".$actionName.$suffix;

                if(!class_exists($className))
                {
                    $className = "m_".$this->moduleName."_".$classType."_".$actionName.$suffix;
                }

                $filePath = $resolver->getFilePathByClassName($className);
                $destPath = $this->getDestTestPath($className);
                $testClassName = $this->getTestClassName($className);

                $result[] = array("className" => $className,
                                  "filePath" => $filePath,
                                  "testClassName" => $testClassName,
                                  "destPath" => $destPath);
            }
            else
            {
                $result = $this->getPhpClassFiles($this->moduleName);
            }
        }
        else
        {
            $result = $this->getPhpClassFiles();
        }

        return $result;
	}

    /**
     * Return an array with the informations to generate the unit test.
     * @param <type> $directory
     * @return <type> array className, filePath, testClassName, destPath
     */
    private function getPhpClassFiles($directory = null)
    {
        $result = array();
        $dir = "";
        $resolver = f_file_Resolver::getInstance()->setMask("*.php")->setRecursive(true);

        if(!is_null($directory))
        {
            $dir = DS.$directory;
        }
        
        $filesPathModule = $resolver->fromDirectory(MODULES_DIR.$dir)->find();
        $filesPathWebApp = $resolver->fromDirectory(WEBAPP_MODULES_DIR.$dir)->find();
        $filesPath = array_merge($filesPathModule, $filesPathWebApp);

        if(is_array($filesPath) && !empty($filesPath))
        {
            foreach($filesPath as $filePath)
            {
                $className = $resolver->getClassNameByFilePath($filePath);

                if(!preg_match("#_tests_#", $className))
                {
                    $destPath = $this->getDestTestPath($className);
                    $testClassName = $this->getTestClassName($className);

                    $result[] = array("className" => $className,
                                      "filePath" => $filePath,
                                      "testClassName" => $testClassName,
                                      "destPath" => $destPath);
                }
            }

            return $result;
        }
    }

    /**
     * Get the destination path for the unit test's creation
     * @param <type> $className
     * @return <type> string $destPath
     */
    private function getDestTestPath($className)
    {
        $tab = explode("_", $className);
        $firstChar = $tab[0];
        
        $directory = $firstChar == "w" ? WEBAPP_MODULES_DIR : MODULES_DIR;
        unset($tab[0]);
        
        array_splice($tab, 1, 0, 'tests');

        $destPath = $directory.DS.implode(DS, $tab)."Test.class.php";

        $folderPath = dirname($destPath);
        if(!is_dir($folderPath))
        {
            mkdir($folderPath, 0755, true);
        }

        return $destPath;
    }

    /**
     * Return the test class name
     * @param <type> $className
     * @return <type> string $className
     */
    private function getTestClassName($className)
    {
        $tab = explode("_", $className);
        array_splice($tab, 2, 0, 'tests');
        return implode("_", $tab)."Test";
    }
}